package com.xsjiong.jaript;

import com.xsjiong.jaript.lexer.JSymbols;
import com.xsjiong.jaript.utils.JReflector;
import com.xsjiong.jaript.utils.JUtils;

import java.lang.reflect.Method;

public class JExecutor {
	private byte[] C;
	private JStringPool P;
	private JContext cx;
	private int I;
	private int Length;
	private boolean SV;
	private Object[] Variables = null;
	private Class<?>[] Variable;

	public JExecutor(JContext cx) {
		this.cx = cx;
		Variables = new Object[cx.getVariableTableSize()];
	}

	void setVariableTableSize(int size) {
		Variables = null;
		System.gc();
		Variables = new Object[size];
	}

	private int getInt() {
		return JUtils.BytesToInt(C[I++], C[I++], C[I++], C[I++]);
	}

	private short getShort() {
		return JUtils.BytesToShort(C[I++], C[I++]);
	}

	private float getFloat() {
		return JUtils.BytesToFloat(C[I++], C[I++], C[I++], C[I++]);
	}

	private double getDouble() {
		return JUtils.BytesToDouble(C[I++], C[I++], C[I++], C[I++], C[I++], C[I++], C[I++], C[I++]);
	}

	private boolean getBoolean() {
		return C[I++] == 1;
	}

	private char getChar() {
		return (char) JUtils.BytesToShort(C[I++], C[I++]);
	}

	private long getLong() {
		return JUtils.BytesToLong(C[I++], C[I++], C[I++], C[I++], C[I++], C[I++], C[I++], C[I++]);
	}

	private int getVariable() {
		if (SV) return getShort();
		else return getInt();
	}

	private String getString() {
		return P.getString(getInt());
	}

	private static void RE(String des) {
		throw new RuntimeException(des);
	}

	public synchronized void run(byte[] code, JStringPool pool) {
		if (code.length == 0) return;
		this.C = code;
		this.P = pool;
		Length = C.length;
		I = 0;
		for (int i = 0; i < Variables.length; i++)
			Variables[i] = 0;
		SV = cx.isUsingShortVariableSize();
		while (true) {
			switch (C[I++]) {
				case JCode.CONST_INT:
					Variables[getVariable()] = getInt();
					break;
				case JCode.CONST_SHORT:
					Variables[getVariable()] = getShort();
					break;
				case JCode.CONST_BYTE:
					Variables[getVariable()] = C[I++];
					break;
				case JCode.CONST_FLOAT:
					Variables[getVariable()] = getFloat();
					break;
				case JCode.CONST_DOUBLE:
					Variables[getVariable()] = getDouble();
					break;
				case JCode.CONST_BOOLEAN:
					Variables[getVariable()] = getBoolean();
					break;
				case JCode.CONST_LONG:
					Variables[getVariable()] = getLong();
					break;
				case JCode.CONST_CHAR:
					Variables[getVariable()] = getChar();
					break;
				case JCode.MOVE:
					//System.out.println(getVariable() +" "+getVariable());
					Variables[getVariable()] = Variables[getVariable()];
					break;
				case JCode.OP: {
					byte s = C[I++];
					int target = getVariable();
					Object a = Variables[getVariable()];
					Object b = Variables[getVariable()];
					JOperator op = JOperator.getOperator(a);
					if (op == null)
						RE("无法找到 " + a.getClass().getName() + " " + JSymbols._GetSymbolName(s) + " " + b.getClass().getName() + " 的运算符");
					else
						Variables[target] = op.calc(a, b, s);
					break;
				}
				case JCode.INVOKE:{
					String cln = getString();
					String me = null;
					Class cl = null;
					Method m;
					try {
						cl = JReflector.getClass(cln);
						me = getString();
						//m = cl.getMethod(me);
					} catch (ClassNotFoundException e) {
						throw new RuntimeException("不能找到类 " + cln, e);
					}
					break;
				}
			}
			if (I == Length) break;
		}
	}
}
